Detailed embedded Linux device driver module_init

I have been writing Linux drivers, are defined in accordance with a fixed format, an initialization and exit functions, the book told me that these two functions will be called, as to why it will be called, where the call, it has been unclear.

By chance, see the code inside the blob, which has a list of initialization functions. According to the general programming idea, the initialization function of each part is called in a fixed function such as:

Void init(void)

{

Init_a();

Init_b();

}

If you add an initialization function, add another line after init_b():

Init_c();

This can really complete our function, but there is a certain problem, that is, you can not add the initialization function independently, each time you add a new function must modify the init function, the initialization function in the blob is completely independent, as long as a macro To modify it:

Void init_a(void)

{

}

__initlist(init_a, 1);

Is it through this macro to implement a list of initialization functions?

First look at the definition of __initlist:

#define __init __attribute__((unused, __section__(".initlist")))

#define __initlist(fn, lvl) /

Static initlist_t __init_##fn __init = { /

Magic: INIT_MAGIC, /

Callback: fn, /

Level: lvl }

It seems to define a structure, save the pointer to the initialization function, nothing special. Please note: __section__(".initlist")

What does this property do? It tells the linker that this variable is stored in the .initlist section. If all initialization functions use this macro, then each function will have a corresponding initlist_t structure variable stored in the .initlist section. That is, we can find pointers to all initialization functions in the .initlist section. How to find the address of the .initlist section?

Extern u32 __initlist_start;

Extern u32 __initlist_end;

These two variables work, __initlist_start is the beginning of the .initlist section, and __initlist_end is the end. With these two variables we can access all initialization functions.

What are these two variables defined there?

In a connector script file

. = ALIGN(4);

.initlist : {

__initlist_start = .;

*(.initlist)

__initlist_end = .;

}

The values ​​of these two variables are exactly defined at the start and end addresses of the .initlist section, so we can access all the initialization functions through these two variables.

Similarly, the kernel also uses this method, so we write drivers more independent, do not have to add our own code in a fixed place to call our own initialization function and exit function, the connector has been done for us Now. Of course, module_init has other features, such as: After our initialization function completes the initialization, the space occupied by the code will be released. Why is this? Today is late, write it again next time.

A large part of the code in the Linux kernel is device driver code. These driver codes have initialization and deinitialization functions. These codes are usually executed only once. In order to use the memory more efficiently, the memory occupied by these codes can be released.

Linux does this by adding __init attributes to functions that only need to be initialized once. At the later stage of kernel initialization, all memory occupied by these function codes is released. How does it do it? Those who saw module_init and module_exit know that the linker puts the function with the __init attribute in the same section and releases the entire section after it is used.

Say no word, we look at the source code, init/main.c start_kernel is the first c function into the kernel, in the last line of this function is

Rest_init();

Static void rest_init(void)

{

Kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);

Unlock_kernel();

Cpu_idle();

}

Created a kernel thread, the main function init, the code is as follows:

Static int init(void * unused)

{

Lock_kernel();

Do_basic_setup();

Prepare_namespace();

/*

* Ok, we have completed the initial bootup, and

* we're essentially up and running. Get rid of the

* initmem segments and start the user-mode stuff..

*/

Free_initmem();

Unlock_kernel();

The red line of code is used to release initialization code and data.

Void free_initmem(void)

{

#ifndef CONFIG_XIP_ROM

If (!machine_is_integrator()) {

Free_area((unsigned long)(&__init_begin),

(unsigned long)(&__init_end),

"init");

}

#endif

}

The next thing is kernel memory management.

************************************************** ************************************************** ****

The driver module written under Linux must not be unfamiliar with this macro. The module_init macro expands if the MODULE macro is not defined. If this macro is not defined, it basically indicates that your module is to be compiled into the kernel (obj-y).

1. In the case where MODULE is not defined, module_init is defined as follows:

#define module_init(x) __initcall(x);

because

#define __initcall(fn) device_initcall(fn)

#define device_initcall(fn) __define_initcall("6",fn,6)

#define __define_initcall(level,fn,id) \

Static initcall_t __initcall_##fn##id __used \

__attribute__((__section__(".initcall" level ".init"))) = fn

So module_init(x) eventually expands to:

Static initcall_t __initcall_##fn##id __used \

__attribute__((__section__(".initcall" level ".init"))) = fn

More straightforwardly, assuming that your module's driver initialization function is int gpio_init(void), module_init(gpio_init) is actually equal to:

Static initcall_t __initcall_gpio_init_6 __used __attribute__((__section__(".initcall6.init"))) = gpio_init;

It is to declare a variable __initcall_gpio_init_6 of type initcall_t(typedef int (*initcall_t)(void)) function pointer and assign gpio_init to it.

The special point of the function pointer variable declaration here is that this variable is placed in a section called ".initcall6.init". Next combine the vmlinux.lds

.initcall.init : AT(ADDR(.initcall.init) - (0xc0000000 -0x00000000)) {

__initcall_start = .;

*(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s .init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs. Init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init)

__initcall_end = .;

}

And do_initcalls:

Static void __init do_initcalls(void)

{

Initcall_t *call;

For (call = __initcall_start; call < __initcall_end; call++)

Do_one_initcall(*call);

/* Make sure there is no pending stuff from the initcall sequence */

Flush_scheduled_work();

}

It is not difficult to understand when the initialization function in module_init in your module is called: start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls() during system startup.

2. In the case where MODULE is defined (most driver modules that can be dynamically loaded belong to this, obj-m), module_init is defined as follows:

#define module_init(initfn) \

Static inline initcall_t __inittest(void) \

{return initfn; } \

Int init_module(void) __attribute__((alias(#initfn)));

The key point of this macro definition is the following sentence, initfn is changed to init_module by alias. The definition of __inittest in front of it is actually a trick to perform some kind of static type checking on initfn. If you define the module initialization function as, for example, void gpio_init(void) or int gpio_init(int), then compile it. There will be similar warnings below:

GPIO/fsl-gpio.c: In function '__inittest':

GPIO/fsl-gpio.c:46: warning: return from incompatible pointer type

Module_init module init function is uniformly aliased to init_module, so that insmod later, the system will call sys_init_module () to find the init_module function entry address.

If objdump -t gpio.ko, you will find that init_module and gpio_init are at the same address offset. In short, in this case the module's initialization function is called when insmod.

LED Hotel Projector

With the advancement of technology, LED technology has been applied to projectors. There are many good domestic LED projector manufacturers in the market. For example, Shenzhen Resources has perfectly combined this technology with DLP technology to make it portable and compact. Because of its low power consumption and heat generation, it is more widely used in life and in personal business. The same goes for LED hotel projectors.

portable led projector,led home theater projector,led holiday projector,led room light projector,led 4k projectors

Shenzhen Happybate Trading Co.,LTD , https://www.happybateprojectors.com